import { Button } from "antd";
import { useCallback, useEffect, useRef, useState } from 'react';

const audioFileType = 'audio/ogg; codecs=opus';

const AudioPlayer = (props: { url: string; }) => {
    const audioRef = useRef<HTMLAudioElement>(null);

    return (
        <div>
            <audio
                ref={audioRef}
                controls={true}
            >
                <source src={props.url} type="audio/ogg" />
            </audio>
        </div>
    );
}

const AudioRecorderDemo = () => {
    /** 是否在讲话 */
    const [audioList, setAudioList] = useState<string[]>([]);
    const [talking, setTalking] = useState(false);
    const chunksRef = useRef<Blob[]>([]);
    const mediaRecorderRef = useRef<MediaRecorder>();

    /** 移除事件 */
    const removeEvents = () => {
        mediaRecorderRef.current?.removeEventListener('stop', onstop, false);
        mediaRecorderRef.current?.removeEventListener('dataavailable', dataavailable, false);
    }

    useEffect(() => {
        navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => {
            // 创建 MediaRecorder 对象
            const mediaRecorder = new MediaRecorder(stream);
            mediaRecorderRef.current = mediaRecorder;
            mediaRecorder.addEventListener('stop', onstop, false);
            mediaRecorder.addEventListener('dataavailable', dataavailable, false);
        });

        return () => {
            removeEvents();
            setAudioList(prevList => {
                prevList.forEach(item => URL.revokeObjectURL(item));
                return [];
            });
        }
    }, []);

    /** 
     * 在 MediaRecorder 对象的 "dataavailable" 事件中获取录制的音频数据
     * https://developer.mozilla.org/zh-CN/docs/Web/API/MediaRecorder/dataavailable_event
    */
    const dataavailable = useCallback((e: BlobEvent) => {
        chunksRef.current.push(e.data);
    }, []);

    const onstop = useCallback(() => {
        const chunks = chunksRef.current;
        const blob = new Blob(chunks, { type: audioFileType });
        var audioURL = URL.createObjectURL(blob);
        setAudioList(prevList => [audioURL, ...prevList]);
        chunksRef.current = [];
    }, []);

    const start = () => {
        setTalking(true);
        mediaRecorderRef.current?.start();
    }

    const stop = () => {
        setTalking(false);
        /** 移除事件 */
        mediaRecorderRef.current?.stop();
    }

    const record = () => {
        talking ? stop() : start();
    }

    return (
        <div style={{ width: 600, }}>
            {/* 录音展示的区域 */}
            <div style={{
                height: 600,
                overflow: 'auto',
                borderRadius: '4px',
                backgroundColor: 'lightgray'
            }}>
                {
                    audioList.map(blobUrl => {
                        return (
                            <AudioPlayer url={blobUrl} key={blobUrl} />
                        );
                    })
                }
            </div>

            <div style={{ textAlign: 'center', marginTop: 24 }}>
                <Button onClick={record}>
                    { talking ? '完成录音' : '开始录音' }
                </Button>
            </div>
        </div>
    );
};

export default AudioRecorderDemo;
